/*
 *	NEXTSTEP specific routines for RasMol
 *		(c) 1995 Andreas Windemuth 
 */
 
#import "objc/NXBundle.h"

#define GRAPHICS
#include "rasnext/RasView.h"

//	Link back to RasView object
RasView *rasView=NULL;

//	direct character output to text port
void NXWriteChar(char ch)
{
    [rasView putChar:ch];
}

void NXWriteString(char *ptr)
{
    [rasView show:ptr];
}

//	Timing function
Real realtime(void)
{
    struct timeval tv;
    struct timezone tzv;

    gettimeofday(&tv, &tzv);
/*    debug("Time: %d seconds, %d microseconds, % 15.3f\n",
	tv.tv_sec, tv.tv_usec, (double)tv.tv_sec + 1e-6*(double)tv.tv_usec);  */
    return (Real)tv.tv_sec + 1e-6*(Real)tv.tv_usec;
}

//	Find bundeled files such as rasmol.hlp
FILE *openResourceFile(const char *fn, char *path, int len)
{
    char buf[MAXPATHLEN+1];
    
    if (![[NXBundle mainBundle] getPath:buf forResource:fn ofType:NULL]) return NULL;
    if (path) {
	if (strlen(buf)>len) {
	    if( CommandActive ) WriteChar('\n');
	    CommandActive = False;
	    WriteString("Unable to find RasMol help file!\n");
	}
	strcpy(path, buf);
    }
    return fopen(buf, "r");
}

// no color maps
void AllocateColourMap()
{
}

//	This should be in rasmol core, I guess
int CreateImage()
{
    register Long size, temp;

    if( FBuffer ) free(FBuffer);
    size = (Long)XRange*YRange*sizeof(Pixel);
    FBuffer = (Pixel*)malloc( size+32 );
    [rasView initBitmap];
    return( (int)FBuffer );
}


//	Flush to screen
void TransferImage()
{
    Real t = realtime();
#ifdef TWOBIT
    { int i, j; Byte *p, *q;
	q = FBuffer;
	for (i=0; i<YRange; i++) {
	    p = tbuf + i*((XRange>>2)+1);
	    for (j=0; j<(XRange>>2); j++) {
		*p = *(q++)&192;
		*p |= (*(q++)&192)>>2;
		*p |= (*(q++)&192)>>4;
		*(p++) |= (*(q++)&192)>>6;
	    }
	    *p = 0;
	    for (j=0; j<(XRange%4); j++) *p |= (*(q++)&192)>>(j<<1);
	}
    }
//    printf("Buffer transferred: %g\n", realtime()-t);
#endif
    [rasView display];
    NXPing();
    [rasView setMeter:2 value:realtime()-t];
}


void ClearImage()
{
}


//	Replaced by NEXTSTEP print mechanism
int PrintImage()
{
    return( True );
}


int ClipboardImage()
{
}


void UpdateScrollBars()
{
}


void SetMouseMode( mode )
    int mode;
{
}


int LookUpColour( name, r, g, b )
    char *name; int *r, *g, *b;
{
    return( False );
}    


void EnableMenus( flag )
    int flag;
{
}


int OpenDisplay( x, y )
    int x, y;
{
    int i;
    
    UseHourGlass = True;
    DisableMenu = False;
    MouseMode = MMRasMol;

    for( i=0; i<8; i++ )
	 DialValue[i] = 0.0;

    ULut[0] = True;
    RLut[0] = GLut[0] = BLut[0] = 0;
    XRange = x;   WRange = XRange>>1;
    YRange = y;   HRange = YRange>>1;
    Range = MinFun(XRange,YRange);
        
    /* Initialise Palette! */
    for( i=1; i<256; i++ )
	ULut[i] = False;
    AllocateColourMap();
    UpdateScrollBars();
    
    if (!rasView) return False;
    return(True);                       
}

    
void BeginWait()
{
}


void EndWait()
{
}


void CloseDisplay()
{
}

int FetchEvent( wait )
    int wait;
{
}

void ClampDial( dial, value )
    int dial;  Real value;
{
    register Real temp;

    temp = DialValue[dial] + value;

    if( temp > 1.0 )
    {   DialValue[dial] = 1.0;
    } else if( temp < -1.0 )
    {   DialValue[dial] = -1.0;
    } else DialValue[dial] = temp;
}

void WrapDial( dial, value )
    int dial;  Real value;
{
    register Real temp;

    temp = DialValue[dial] + value;
    while( temp < -1.0 )  temp += 2.0;
    while( temp > 1.0 )   temp -= 2.0;
    DialValue[dial] = temp;
}

//	MouseMove lifted almost unmodified from X-windows version:
#define ShiftMask NX_SHIFTMASK
#define ControlMask NX_CONTROLMASK
#define Button1Mask 1
#define Button2Mask 2
#define Button3Mask 4

void MouseMove( int status, int dx, int dy )
{
    register int index;

/* printf("MouseMove %x %d %d\n", status, dx, dy);
printf("  RasMol: %d, Shift: %d, But1: %d, But2: %d, Ctrl: %d\n",
    MouseMode == MMRasMol, status & ShiftMask, status & Button1Mask,
    status & Button2Mask, status & ControlMask);
*/
    if( MouseMode == MMRasMol )
    {   if( status & ShiftMask )
        {   if( status & Button1Mask ) 
            {   if( dy ) /* Zoom Vertical */
                {   ClampDial( 3, (Real)dy/HRange );
                    ReDrawFlag |= RFZoom;
                }
            } else if( status & (Button2Mask|Button3Mask) )
                if( dx ) /* Z Rotation Horizontal */
                {   WrapDial( 2, (Real)dx/WRange );
                    ReDrawFlag |= RFRotateZ;
                }
        } else if( status & ControlMask )
        {   if( status & Button1Mask )
            {   if( dy ) /* Slab Vertical */
                {   ClampDial( 7, (Real)dy/YRange );
                    ReDrawFlag |= RFSlab;
                }
            }

        } else /* Unmodified! */
            if( status & Button1Mask )
            {   if( dx ) /* Rotate Y Horizontal */
                {   WrapDial( 1, (Real)dx/WRange );
                    index = (DialValue[1]+1.0)*(XRange-48);
/*                    NewScrlX = (index>>1)+16;   */
                    ReDrawFlag |= RFRotateY;
                }

                if( dy ) /* Rotate X Vertical */
                {   WrapDial( 0, (Real)dy/HRange );
                    index = (DialValue[0]+1.0)*(YRange-48);
/*                    NewScrlY = (index>>1)+16;  */
                    ReDrawFlag |= RFRotateX;
                }
            } else if( status & (Button2Mask|Button3Mask) )
            {   if( dx ) /* Translate X Horizontal */
                {   ClampDial( 4, (Real)dx/XRange );
                    ReDrawFlag |= RFTransX;
                }

                if( dy ) /* Translate Y Vertical */
                {   ClampDial( 5, (Real)dy/YRange );
                    ReDrawFlag |= RFTransY;
                }
            }
    } else if( MouseMode==MMQuanta )
    {   if( status & ShiftMask )
        {   if( status & Button1Mask )
            {   if( dy ) /* Slab Vertical */
                {   ClampDial( 7, (Real)dy/YRange );
                    ReDrawFlag |= RFSlab;
                }
            } else if( status & Button2Mask )
            {   if( dx ) /* Translate X Horizontal */
                {   ClampDial( 4, (Real)dx/XRange );
                    ReDrawFlag |= RFTransX;
                }

                if( dy ) /* Translate Y Vertical */
                {   ClampDial( 5, (Real)dy/YRange );
                    ReDrawFlag |= RFTransY;
                }
            } else if( !(status & Button3Mask) )
                if( dy ) /* Zoom Vertical */
                {   ClampDial( 3, (Real)dy/HRange );
                    ReDrawFlag |= RFZoom;
                }
        } else if( status & Button2Mask )
        {   if( dx ) /* Rotate Y Horizontal */
            {   WrapDial( 1, (Real)dx/WRange );
                index = (DialValue[1]+1.0)*(XRange-48);
/*                NewScrlX = (index>>1)+16;  */
                ReDrawFlag |= RFRotateY;
            }

            if( dy ) /* Rotate X Vertical */
            {   WrapDial( 0, (Real)dy/HRange );
                index = (DialValue[0]+1.0)*(YRange-48);
/*                NewScrlY = (index>>1)+16;  */
                ReDrawFlag |= RFRotateX;
            }
        } else if( status & Button3Mask )
            if( dx ) /* Z Rotation Horizontal */
            {   WrapDial( 2, (Real)dx/WRange );
                ReDrawFlag |= RFRotateZ;
            }
    } else /* MMInsight */
        switch( status & (Button1Mask|Button2Mask|Button3Mask) )
        {   case( Button1Mask ):
                    if( dx ) /* Rotate Y Horizontal */
                    {   WrapDial( 1, (Real)dx/WRange );
                        index = (DialValue[1]+1.0)*(XRange-48);
/*                        NewScrlX = (index>>1)+16;  */
                        ReDrawFlag |= RFRotateY;
                    }

                    if( dy ) /* Rotate X Vertical */
                    {   WrapDial( 0, (Real)dy/HRange );
                        index = (DialValue[0]+1.0)*(YRange-48);
/*                        NewScrlY = (index>>1)+16;  */
                        ReDrawFlag |= RFRotateX;
                    }
                    break;

            case( Button2Mask ):
                    if( dx ) /* Translate X Horizontal */
                    {   ClampDial( 4, (Real)dx/XRange );
                        ReDrawFlag |= RFTransX;
                    }

                    if( dy ) /* Translate Y Vertical */
                    {   ClampDial( 5, (Real)dy/YRange );
                        ReDrawFlag |= RFTransY;
                    }
                    break;

            case( Button1Mask|Button2Mask ):
                    ClampDial( 3, (Real)dx/WRange - (Real)dy/HRange );
                    ReDrawFlag |= RFZoom;
                    break;

            case( Button1Mask|Button3Mask ):
                    WrapDial( 2, (Real)dx/WRange - (Real)dy/HRange );
                    ReDrawFlag |= RFRotateZ;
                    break;

            case( Button1Mask|Button2Mask|Button3Mask ):
                    ClampDial( 7, (Real)dx/XRange - (Real)dy/YRange );
                    ReDrawFlag |= RFSlab;
                    break;
        }
}

